#ifndef CONF_H_
#define CONF_H_

#include <stdio.h>
#include <boost/logic/tribool.hpp>

#include "conf/node.h"
#include "conf/document.h"
#include "conf/attribute.h"
#include "conf/collection.h"
#include "search.h"
#include "misc.h"
#include "strfuncs.h"

namespace gpyp {

inline std::string create_pid_dir_path(const Glib::ustring &conf_dir) {
  return Glib::build_filename(Glib::filename_from_utf8(conf_dir), "pid");
}
inline std::string create_pid_path(const std::string &pid_dir,
                                   const std::string &name) {
  return Glib::build_filename(pid_dir, name + ".pid");
}
inline std::string prepare_pid_dir_path(const Glib::ustring &conf_dir) {
  std::string path = create_pid_dir_path(conf_dir);
  g_mkdir_with_parents(path.c_str(), 0700);
  return path;
}
inline pid_t load_pid(const Glib::ustring &conf_dir,
                      const std::string   &name) {
  try {
    std::string path = create_pid_path(create_pid_dir_path(conf_dir), name);
    std::string data = Glib::file_get_contents(path);
    return touint(data, 0);
  } catch(...) {
    return 0;
  }
}
inline void save_pid(const Glib::ustring &conf_dir,
                     const std::string   &name,
                     pid_t pid) {
  std::string   pid_dir  = prepare_pid_dir_path(conf_dir);
  std::string   pid_path = create_pid_path(pid_dir, name);
  Glib::ustring pid_s    = tostr(pid);
  g_file_set_contents(pid_path.c_str(), pid_s.c_str(), -1, NULL);
}
inline void remove_pid(const Glib::ustring &conf_dir,
                       const std::string   &name) {
  std::string path = create_pid_path(create_pid_dir_path(conf_dir), name);
  remove(path.c_str());
}

class Search;
typedef boost::shared_ptr<Search> RefSearch;

class ConfMain : public conf::Document {
public:
  class Tooltip : public conf::Element {
  private:
    RefAttributeColor      color_bg_;
    RefAttributeColor      color_fg_;
    RefAttributeColor      color_fr_;
    RefAttributeColor      color_bg_sel_;
    RefAttributeColor      color_fg_sel_;
    RefAttributeColor      color_fr_sel_;
    conf::RefAttributeBool enable_frame_;
    conf::RefAttributeBool enable_frame_sel_;
    conf::RefAttributeInt  xpad_;
    conf::RefAttributeInt  ypad_;

  public:
    inline RefAttributeColor color_bg() {
      return color_bg_;
    }
    inline RefAttributeColor color_fg() {
      return color_fg_;
    }
    inline RefAttributeColor color_fr() {
      return color_fr_;
    }
    inline RefAttributeColor color_bg_sel() {
      return color_bg_sel_;
    }
    inline RefAttributeColor color_fg_sel() {
      return color_fg_sel_;
    }
    inline RefAttributeColor color_fr_sel() {
      return color_fr_sel_;
    }
    inline conf::RefAttributeBool enable_frame() {
      return enable_frame_;
    }
    inline conf::RefAttributeBool enable_frame_sel() {
      return enable_frame_sel_;
    }
    inline conf::RefAttributeInt xpad() {
      return xpad_;
    }
    inline conf::RefAttributeInt ypad() {
      return ypad_;
    }

    Tooltip();
  };
  typedef boost::shared_ptr<Tooltip> RefTooltip;

  class General : public conf::Element {
  private:
    conf::RefAttributeBool run_peercast_;
    conf::RefAttributeBool run_pcraw_proxy_;
    conf::RefAttributeBool avoid_close_;
    conf::RefAttributeStr  statusbar_format_;
    conf::RefAttributeStr  shell_;
    conf::RefAttributeStr  shell_esc_;
    conf::RefAttributeStr  command_prefix_;

    RefAttributeColor      color_positive_;
    RefAttributeColor      color_negative_;
    RefAttributeColor      color_unimportant_;

    conf::RefAttributeStr  font_monospace_;

    RefTooltip             tooltip_;

  public:
    inline conf::RefAttributeBool run_peercast() {
      return run_peercast_;
    }
    inline conf::RefAttributeBool run_pcraw_proxy() {
      return run_pcraw_proxy_;
    }
    inline conf::RefAttributeBool avoid_close() {
      return avoid_close_;
    }
    inline conf::RefAttributeStr statusbar_format() {
      return statusbar_format_;
    }
    inline conf::RefAttributeStr shell() {
      return shell_;
    }
    inline conf::RefAttributeStr shell_esc() {
      return shell_esc_;
    }
    inline conf::RefAttributeStr command_prefix() {
      return command_prefix_;
    }

    inline RefAttributeColor color_positive() {
      return color_positive_;
    }
    inline RefAttributeColor color_negative() {
      return color_negative_;
    }
    inline RefAttributeColor color_unimportant() {
      return color_unimportant_;
    }

    inline conf::RefAttributeStr font_monospace() {
      return font_monospace_;
    }

    inline RefTooltip tooltip() {
      return tooltip_;
    }

    General();
  };
  typedef boost::shared_ptr<General> RefGeneral;

  class ScreenSaver : public conf::Element {
  private:
    conf::RefAttributeBool disable_auto_play_;
    conf::RefAttributeBool mute_;

  public:
    inline conf::RefAttributeBool disable_auto_play() {
      return disable_auto_play_;
    }
    inline conf::RefAttributeBool mute() {
      return mute_;
    }

    ScreenSaver();
  };
  typedef boost::shared_ptr<ScreenSaver> RefScreenSaver;

  class Network : public conf::Element {
  private:
    RefAttributeHost       peercast_server_;
    conf::RefAttributeStr  peercast_server_id_;
    conf::RefAttributeStr  peercast_server_pw_;
    RefAttributeHost       pcraw_proxy_server_;
    RefAttributeUA         useragent_;
    conf::RefAttributeUint timeout_;
    conf::RefAttributeBool disable_ipv6_;
    conf::RefAttributeUint autoretry_limit_;
    conf::RefAttributeUint autoretry_interval_;

  public:
    inline RefAttributeHost peercast_server() {
      return peercast_server_;
    }
    inline conf::RefAttributeStr peercast_server_id() {
      return peercast_server_id_;
    }
    inline conf::RefAttributeStr peercast_server_pw() {
      return peercast_server_pw_;
    }
    inline RefAttributeHost pcraw_proxy_server() {
      return pcraw_proxy_server_;
    }
    inline RefAttributeUA useragent() {
      return useragent_;
    }
    inline conf::RefAttributeUint timeout() {
      return timeout_;
    }
    inline conf::RefAttributeBool disable_ipv6() {
      return disable_ipv6_;
    }
    inline conf::RefAttributeUint autoretry_limit() {
      return autoretry_limit_;
    }
    inline conf::RefAttributeUint autoretry_interval() {
      return autoretry_interval_;
    }

    Network();
  };
  typedef boost::shared_ptr<Network> RefNetwork;

  class PlayerCollection;
  class Player : public conf::Element {
    friend class conf::Collection<Player, PlayerCollection>;
  private:
    conf::RefAttributeStr  icon_;
    conf::RefAttributeStr  name_;
    conf::RefAttributeStr  command_;
    conf::RefAttributeStr  type_;
    conf::RefAttributeBool auto_play_;

  public:
    inline conf::RefAttributeStr icon() {
      return icon_;
    }
    inline conf::RefAttributeStr name() {
      return name_;
    }
    inline conf::RefAttributeStr command() {
      return command_;
    }
    inline conf::RefAttributeStr type() {
      return type_;
    }
    inline conf::RefAttributeBool auto_play() {
      return auto_play_;
    }

    inline bool match_type(const Glib::ustring &type) const {
      if ((*type_).empty()) return true;

      const char *s = (*type_).c_str(), *c = s;
      for(; *c; ++c) {
        if (*c == ',') {
          if (strncasecmp(type.c_str(), s, c - s) == 0) return true;
          s = c + 1;
        }
      }
      return strncasecmp(type.c_str(), s, c - s) == 0;
    }

    inline Player(const Glib::ustring &name) :
      conf::Element(name),
      icon_        ("icon",      ""),
      name_        ("name",      ""),
      command_     ("command",   ""),
      type_        ("type",      ""),
      auto_play_   ("auto_play", false)
    {
      add(icon_);
      add(name_);
      add(command_);
      add(type_);
      add(auto_play_);
    }
  };
  typedef boost::shared_ptr<Player> RefPlayer;
  class PlayerCollection :
    public conf::Collection<Player, PlayerCollection> {
  public:
    struct Preset {
      const char *name;
      const char *command;
      const char *icon;
    };
    static const Preset PRESETS[];

  private:
    Glib::ustring old_play_;
    Glib::ustring old_play2_;
    Glib::ustring old_auto_play_;

  protected:
    virtual RefPlayer on_create_item(const Glib::ustring &name);
    virtual void on_load_default();
    virtual void on_default_loaded();

  public:
    void set_old_play(const Glib::ustring &play);
    void set_old_play2(const Glib::ustring &play2);
    void set_old_auto_play(const Glib::ustring &auto_play);

    inline RefPlayer add_item() {
      return conf::Collection<Player, PlayerCollection>::add_item();
    }
    inline RefPlayer add_item(const Glib::ustring &name,
                              const Glib::ustring &command,
                              const Glib::ustring &icon = Glib::ustring()) {
      RefPlayer player  = add_item();
      player->icon()    = icon;
      player->name()    = name;
      player->command() = command;
      return player;
    }

    inline RefPlayer get_player(const Glib::ustring &type) {
      for(iterator iter = begin(); iter != end(); ++iter) {
        RefPlayer p = *iter;
        if (!*p->auto_play() && p->match_type(type)) return p;
      }
      return RefPlayer();
    }
    inline RefPlayer get_auto_player(const Glib::ustring &type) {
      for(iterator iter = begin(); iter != end(); ++iter) {
        RefPlayer p = *iter;
        if (*p->auto_play() && p->match_type(type)) return p;
      }
      return RefPlayer();
    }
    inline RefPlayer find(const Glib::ustring &name) {
      for(iterator iter = begin(); iter != end(); ++iter) {
        RefPlayer p = *iter;
        if (*p->name() == name) return p;
      }
      return RefPlayer();
    }

    PlayerCollection();
  };
  typedef boost::shared_ptr<PlayerCollection> RefPlayerCollection;

  class Command : public conf::Element {
  private:
    conf::RefAttributeStr command_;

  public:
    inline conf::RefAttributeStr command() {
      return command_;
    }

    Command(const Glib::ustring &name,
            const Glib::ustring &command);
  };
  class RefCommand : public boost::shared_ptr<Command> {
  public:
    inline RefCommand() {
    }
    inline RefCommand(const Glib::ustring &name,
                      const Glib::ustring &command) :
      boost::shared_ptr<Command>(new Command(name, command))
    {
    }
  };
  class BuiltInCommand : public conf::Element {
  public:
    static const char *PRESET_PEERCAST[];
    static const char *PRESET_PCRAW_PROXY[];
    static const char *PRESET_TERMINAL[];
    static const char *PRESET_WEBBROWSER[];
    static const char *PRESET_BBSBROWSER[];

  private:
    Glib::ustring dir_path_;

    RefCommand peercast_;
    RefCommand pcraw_proxy_;
    RefCommand terminal_;
    RefCommand webbrowser_;
    RefCommand bbsbrowser_;

    RefPlayerCollection players_;

  protected:
    virtual void on_start_element(conf::ConfParser &parser,
                                  const char  *element_name,
                                  const char **attribute_names,
                                  const char **attribute_values,
                                  GError     **error);

  public:
    inline RefCommand peercast() {
      return peercast_;
    }
    inline RefCommand pcraw_proxy() {
      return pcraw_proxy_;
    }
    inline RefCommand terminal() {
      return terminal_;
    }
    inline RefCommand webbrowser() {
      return webbrowser_;
    }
    inline RefCommand bbsbrowser() {
      return bbsbrowser_;
    }

    inline RefPlayerCollection players() {
      return players_;
    }

    BuiltInCommand(const Glib::ustring &dir_path);
  };
  typedef boost::shared_ptr<BuiltInCommand> RefBuiltInCommand;

  class Record : public conf::Element {
  public:
    static const char *PRESETS[];

  private:
    conf::RefAttributeStr  command_;
    conf::RefAttributeStr  filename_;
    conf::RefAttributeUint retry_timeout_;
    conf::RefAttributeInt  retry_count_;
    conf::RefAttributeBool retry_ch_exists_;
    conf::RefAttributeBool rm_zero_file_;
    conf::RefAttributeBool term_on_exit_;
    conf::RefAttributeBool kill_on_exit_;

    conf::RefAttributeBool save_log_;
    conf::RefAttributeStr  log_filename_;

  public:
    inline conf::RefAttributeStr command() {
      return command_;
    }
    inline conf::RefAttributeStr filename() {
      return filename_;
    }
    inline conf::RefAttributeUint retry_timeout() {
      return retry_timeout_;
    }
    inline conf::RefAttributeInt retry_count() {
      return retry_count_;
    }
    inline conf::RefAttributeBool retry_ch_exists() {
      return retry_ch_exists_;
    }
    inline conf::RefAttributeBool rm_zero_file() {
      return rm_zero_file_;
    }
    inline conf::RefAttributeBool term_on_exit() {
      return term_on_exit_;
    }
    inline conf::RefAttributeBool kill_on_exit() {
      return kill_on_exit_;
    }

    inline conf::RefAttributeBool save_log() {
      return save_log_;
    }
    inline conf::RefAttributeStr log_filename() {
      return log_filename_;
    }

    Record();
  };
  typedef boost::shared_ptr<Record> RefRecord;

  class PresetColors;
  class PresetColor : public conf::Element {
    friend class conf::Collection<PresetColor, PresetColors>;
  private:
    RefAttributeColor color_;

  public:
    inline RefAttributeColor color() {
      return color_;
    }

    PresetColor(const Glib::ustring &name);
  };
  typedef boost::shared_ptr<PresetColor> RefPresetColor;

  class PresetColors : public conf::Collection<PresetColor, PresetColors> {
  protected:
    virtual void on_load_default();
    virtual RefPresetColor on_create_item(const Glib::ustring &name);

  public:
    RefPresetColor add_item(const Color &color);
    RefPresetColor add_item(const Glib::ustring &color);

    PresetColors(const Glib::ustring &name);
  };
  typedef boost::shared_ptr<PresetColors> RefPresetColors;

  class Terminal : public conf::Element {
  private:
    conf::RefAttributeUint columns_;
    conf::RefAttributeUint rows_;

    RefAttributeColor color_foreground_;
    RefAttributeColor color_background_;
    RefAttributeColor color_cursor_;
    RefAttributeColor color_highlight_;

    RefAttributeColor color_palette1_;
    RefAttributeColor color_palette2_;
    RefAttributeColor color_palette3_;
    RefAttributeColor color_palette4_;
    RefAttributeColor color_palette5_;
    RefAttributeColor color_palette6_;
    RefAttributeColor color_palette7_;
    RefAttributeColor color_palette8_;
    RefAttributeColor color_palette9_;
    RefAttributeColor color_palette10_;
    RefAttributeColor color_palette11_;
    RefAttributeColor color_palette12_;
    RefAttributeColor color_palette13_;
    RefAttributeColor color_palette14_;
    RefAttributeColor color_palette15_;
    RefAttributeColor color_palette16_;

  public:
    inline conf::RefAttributeUint columns() {
      return columns_;
    }
    inline conf::RefAttributeUint rows() {
      return rows_;
    }

    inline RefAttributeColor color_foreground() {
      return color_foreground_;
    }
    inline RefAttributeColor color_background() {
      return color_background_;
    }
    inline RefAttributeColor color_cursor() {
      return color_cursor_;
    }
    inline RefAttributeColor color_highlight() {
      return color_highlight_;
    }

    inline RefAttributeColor color_palette1() {
      return color_palette1_;
    }
    inline RefAttributeColor color_palette2() {
      return color_palette2_;
    }
    inline RefAttributeColor color_palette3() {
      return color_palette3_;
    }
    inline RefAttributeColor color_palette4() {
      return color_palette4_;
    }
    inline RefAttributeColor color_palette5() {
      return color_palette5_;
    }
    inline RefAttributeColor color_palette6() {
      return color_palette6_;
    }
    inline RefAttributeColor color_palette7() {
      return color_palette7_;
    }
    inline RefAttributeColor color_palette8() {
      return color_palette8_;
    }
    inline RefAttributeColor color_palette9() {
      return color_palette9_;
    }
    inline RefAttributeColor color_palette10() {
      return color_palette10_;
    }
    inline RefAttributeColor color_palette11() {
      return color_palette11_;
    }
    inline RefAttributeColor color_palette12() {
      return color_palette12_;
    }
    inline RefAttributeColor color_palette13() {
      return color_palette13_;
    }
    inline RefAttributeColor color_palette14() {
      return color_palette14_;
    }
    inline RefAttributeColor color_palette15() {
      return color_palette15_;
    }
    inline RefAttributeColor color_palette16() {
      return color_palette16_;
    }

    inline RefAttributeColor get_color_palette(size_t idx) {
      switch(idx) {
      case  0: return color_palette1_;
      case  1: return color_palette2_;
      case  2: return color_palette3_;
      case  3: return color_palette4_;
      case  4: return color_palette5_;
      case  5: return color_palette6_;
      case  6: return color_palette7_;
      case  7: return color_palette8_;
      case  8: return color_palette9_;
      case  9: return color_palette10_;
      case 10: return color_palette11_;
      case 11: return color_palette12_;
      case 12: return color_palette13_;
      case 13: return color_palette14_;
      case 14: return color_palette15_;
      case 15: return color_palette16_;
      }
      return RefAttributeColor();
    }

    Terminal();
  };
  typedef boost::shared_ptr<Terminal> RefTerminal;

  class Alsa : public conf::Element {
  private:
    conf::RefAttributeStr card_;
    conf::RefAttributeStr dev_;
    conf::RefAttributeStr buf_size_;

  public:
    inline conf::RefAttributeStr card() {
      return card_;
    }
    inline conf::RefAttributeStr dev() {
      return dev_;
    }
    inline conf::RefAttributeStr buf_size() {
      return buf_size_;
    }

    Alsa();
  };
  typedef boost::shared_ptr<Alsa> RefAlsa;
  class Pulse : public conf::Element {
  private:
    conf::RefAttributeStr server_;
    conf::RefAttributeStr sink_;

  public:
    inline conf::RefAttributeStr server() {
      return server_;
    }
    inline conf::RefAttributeStr sink() {
      return sink_;
    }

    Pulse();
  };
  typedef boost::shared_ptr<Pulse> RefPulse;
  class Esd : public conf::Element {
  private:
    conf::RefAttributeStr host_;

  public:
    inline conf::RefAttributeStr host() {
      return host_;
    }

    Esd();
  };
  typedef boost::shared_ptr<Esd> RefEsd;
  class Oss : public conf::Element {
  private:
    conf::RefAttributeStr dsp_;

  public:
    inline conf::RefAttributeStr dsp() {
      return dsp_;
    }

    Oss();
  };
  typedef boost::shared_ptr<Oss> RefOss;
  class Sound : public conf::Element {
  private:
    conf::RefAttributeStr  driver_;
    conf::RefAttributeBool mute_;

    RefAlsa     alsa_;
    RefPulse    pulse_;
    RefEsd      esd_;
    RefOss      oss_;

  public:
    inline conf::RefAttributeStr driver() {
      return driver_;
    }
    inline conf::RefAttributeBool mute() {
      return mute_;
    }

    inline RefAlsa alsa() {
      return alsa_;
    }
    inline RefPulse pulse() {
      return pulse_;
    }
    inline RefEsd esd() {
      return esd_;
    }
    inline RefOss oss() {
      return oss_;
    }

    Sound();
  };
  typedef boost::shared_ptr<Sound> RefSound;

  class Migemo : public conf::Element {
  private:
    RefAttributeMigemoMode mode_;
    conf::RefAttributeStr  encoding_;
    conf::RefAttributeUint min_length_;
    conf::RefAttributeStr  dict_path_;
    conf::RefAttributeStr  dict_path_user_;
    conf::RefAttributeStr  url_;

  public:
    inline RefAttributeMigemoMode mode() {
      return mode_;
    }
    inline conf::RefAttributeStr encoding() {
      return encoding_;
    }
    inline conf::RefAttributeUint min_length() {
      return min_length_;
    }
    inline conf::RefAttributeStr dict_path() {
      return dict_path_;
    }
    inline conf::RefAttributeStr dict_path_user() {
      return dict_path_user_;
    }
    inline conf::RefAttributeStr url() {
      return url_;
    }

    Migemo();
  };
  typedef boost::shared_ptr<Migemo> RefMigemo;

  class TextEditor : public conf::Element {
  private:
    RefSearch search_;

  public:
    inline RefSearch search() {
      return search_;
    }

    inline TextEditor()  :
      conf::Element("texteditor"),
      search_      (new Search("search"))
    {
      add(search_);
    }
  };
  typedef boost::shared_ptr<TextEditor> RefTextEditor;

  class ConfigView : public conf::Element {
  private:
    RefSearch search_;

  public:
    inline RefSearch search() {
      return search_;
    }

    inline ConfigView() :
      conf::Element("configview"),
      search_      (new Search("search"))
    {
      add(search_);
    }
  };
  typedef boost::shared_ptr<ConfigView> RefConfigView;

private:
  static const char *FILE_NAME;

  Glib::ustring       dir_path_;

  RefGeneral        general_;
  RefScreenSaver    screensaver_;
  RefNetwork        network_;
  RefBuiltInCommand command_;
  RefRecord         record_;
  RefPresetColors   preset_colors_;
  RefTerminal       terminal_;
  RefSound          sound_;
  RefMigemo         migemo_;
  RefTextEditor     text_editor_;
  RefConfigView     config_view_;

  static bool chk_numeric_command_args(RefCommand           command,
                                       const Glib::ustring &replacement);

protected:
  virtual void on_postload();

public:
  inline RefGeneral general() {
    return general_;
  }
  inline RefScreenSaver screensaver() {
    return screensaver_;
  }
  inline RefNetwork network() {
    return network_;
  }
  inline RefBuiltInCommand command() {
    return command_;
  }
  inline RefRecord record() {
    return record_;
  }
  inline RefPresetColors preset_colors() {
    return preset_colors_;
  }
  inline RefTerminal terminal() {
    return terminal_;
  }
  inline RefSound sound() {
    return sound_;
  }
  inline RefMigemo migemo() {
    return migemo_;
  }
  inline RefTextEditor text_editor() {
    return text_editor_;
  }
  inline RefConfigView config_view() {
    return config_view_;
  }

  ConfMain(const Glib::ustring &dir_path);
};
typedef boost::shared_ptr<ConfMain> RefConfMain;

class ConfMenu : public conf::Document {
public:
  class Menu;
  typedef boost::shared_ptr<Menu> RefMenu;

  enum ItemType {
    ITEM_TYPE_ROOT,
    ITEM_TYPE_COMMAND,
    ITEM_TYPE_SEPARATOR,
    ITEM_TYPE_SPECIAL,
  };

  enum SpecialType {
    SPECIAL_TYPE_PLAYWITH,
    SPECIAL_TYPE_INVALID
  };
  class AttributeSPType :
    public conf::AttributeEnum<SpecialType, AttributeSPType> {
    friend class conf::AttributeEnum<SpecialType, AttributeSPType>;
  protected:
    static NameTable _name_table[];

  public:
    inline AttributeSPType(const Glib::ustring &name, SpecialType defval) :
      conf::AttributeEnum<SpecialType, AttributeSPType>(name, defval)
    {
    }
  };
  typedef conf::RefAttributeEnum<AttributeSPType> RefAttributeSPType;

  class Menu : public conf::Collection<Menu, Menu> {
    friend class conf::Collection<Menu, Menu>;
  private:
    static const char *NAME_COMMAND;
    static const char *NAME_SEPARATOR;
    static const char *NAME_SPECIAL;

  private:
    ItemType type_;

    conf::RefAttributeStr icon_;
    conf::RefAttributeStr label_;
    conf::RefAttributeStr command_;
    RefAttributeSPType    sptype_;

  protected:
    virtual void on_start_element(conf::ConfParser &parser,
                                  const char  *element_name,
                                  const char **attribute_names,
                                  const char **attribute_values,
                                  GError     **error);

    virtual void on_add_item(RefItem item);
    virtual RefMenu on_create_item(const Glib::ustring &item_name);

  public:
    inline ItemType get_type() const {
      return type_;
    }

    inline conf::RefAttributeStr icon() {
      return icon_;
    }
    inline conf::RefAttributeStr label() {
      return label_;
    }
    inline conf::RefAttributeStr command() {
      return command_;
    }
    inline RefAttributeSPType sptype() {
      return sptype_;
    }

    inline bool has_children() const {
      return size() != 0;
    }

    RefMenu add_item();
    RefMenu add_item(const Glib::ustring &label,
                     const Glib::ustring &command = Glib::ustring(),
                     const Glib::ustring &icon = Glib::ustring());
    inline RefMenu add_item(const Glib::ustring &label,
                            const Glib::ustring &command,
                            const Gtk::StockID  &stock_id) {
      return add_item(label, command, stock_id.get_string());
    }
    inline RefMenu add_item(const Glib::ustring &label,
                            const Gtk::StockID  &stock_id) {
      return add_item(label, Glib::ustring(), stock_id.get_string());
    }
    RefMenu add_separator();
    RefMenu add_special(const Glib::ustring &label,
                        SpecialType          sptype,
                        const Glib::ustring &icon = Glib::ustring());

    Menu(const Glib::ustring &name, ItemType type);
  };

private:
  static const char *FILE_NAME;

  RefMenu yp_;
  RefMenu ch_;
  RefMenu tool_;
  RefMenu text_;
  RefMenu proc_;
  RefMenu pc_relay_;
  RefMenu pc_connection_;
  RefMenu webview_;

protected:
  bool chk_uptest_command(RefMenu menu);

  virtual void on_postload();

public:
  inline RefMenu yp() {
    return yp_;
  }
  inline RefMenu ch() {
    return ch_;
  }
  inline RefMenu tool() {
    return tool_;
  }
  inline RefMenu text() {
    return text_;
  }
  inline RefMenu proc() {
    return proc_;
  }
  inline RefMenu pc_relay() {
    return pc_relay_;
  }
  inline RefMenu pc_connection() {
    return pc_connection_;
  }
  inline RefMenu webview() {
    return webview_;
  }

  ConfMenu(const Glib::ustring &dir_path);
};
typedef boost::shared_ptr<ConfMenu> RefConfMenu;

class ConfFavorite : public conf::Document {
private:
  static const char *FILE_NAME;

public:
  ConfFavorite(const Glib::ustring &dir_path);
};
typedef boost::shared_ptr<ConfFavorite> RefConfFavorite;

class KeyBind;
typedef boost::shared_ptr<KeyBind> RefKeyBind;

class ConfInput : public conf::Document {
public:
  class InputMouse : public conf::Element {
  private:
    ConfMain::RefCommand double_click_;
    ConfMain::RefCommand button2_;

    ConfMain::RefCommand button6_;
    ConfMain::RefCommand button7_;
    ConfMain::RefCommand button8_;
    ConfMain::RefCommand button9_;
    ConfMain::RefCommand button10_;
    ConfMain::RefCommand button11_;
    ConfMain::RefCommand button12_;
    ConfMain::RefCommand button13_;
    ConfMain::RefCommand button14_;
    ConfMain::RefCommand button15_;
    ConfMain::RefCommand button16_;
    ConfMain::RefCommand button17_;
    ConfMain::RefCommand button18_;
    ConfMain::RefCommand button19_;
    ConfMain::RefCommand button20_;

  public:
    inline ConfMain::RefCommand double_click() {
      return double_click_;
    }
    inline ConfMain::RefCommand button2() {
      return button2_;
    }
    inline ConfMain::RefCommand button6() {
      return button6_;
    }
    inline ConfMain::RefCommand button7() {
      return button7_;
    }
    inline ConfMain::RefCommand button8() {
      return button8_;
    }
    inline ConfMain::RefCommand button9() {
      return button9_;
    }

    inline ConfMain::RefCommand get_button(size_t button) {
      switch(button) {
      case 6:  return button6_;
      case 7:  return button7_;
      case 8:  return button8_;
      case 9:  return button9_;
      case 10: return button10_;
      case 11: return button11_;
      case 12: return button12_;
      case 13: return button13_;
      case 14: return button14_;
      case 15: return button15_;
      case 16: return button16_;
      case 17: return button17_;
      case 18: return button18_;
      case 19: return button19_;
      case 20: return button20_;
      default: return ConfMain::RefCommand();
      }
    }

    InputMouse(const Glib::ustring &double_click = Glib::ustring(),
               const Glib::ustring &button2 = Glib::ustring());
  };
  class RefInputMouse : public boost::shared_ptr<InputMouse> {
  public:
    inline ConfMain::RefCommand operator[](size_t button) {
      return (*this)->get_button(button);
    }

    inline RefInputMouse() {
    }
    inline RefInputMouse(InputMouse *ptr) :
      boost::shared_ptr<InputMouse>(ptr)
    {
    }
    inline RefInputMouse(const RefInputMouse &im) :
      boost::shared_ptr<InputMouse>(im)
    {
    }
  };

  class InputEntry;
  typedef boost::shared_ptr<InputEntry> RefInputEntry;
  class InputEntry : public conf::Element {
  private:
    RefInputMouse mouse_;
    RefKeyBind    key_;

  public:
    inline RefInputMouse mouse() {
      return mouse_;
    }
    inline RefKeyBind key() {
      return key_;
    }

    InputEntry(const Glib::ustring &name,
               InputMouse          *mouse,
               KeyBind             *key);
  };

  class OldKeyProxy : public conf::Element {
  private:
    ConfInput &input_;

  protected:
    virtual void on_start_element(conf::ConfParser &parser,
                                  const char  *element_name,
                                  const char **attribute_names,
                                  const char **attribute_values,
                                  GError     **error);

  public:
    OldKeyProxy(ConfInput &input);
  };

private:
  static const char *FILE_NAME;

  RefInputEntry mainwindow_;
  RefInputEntry channellist_;
  RefInputEntry process_;
  RefInputEntry peercast_;
  RefInputEntry pc_relay_;
  RefInputEntry pc_connection_;
  RefInputEntry text_editor_;
  RefInputEntry search_;
  RefInputEntry searchbar_;
  RefInputEntry webview_;

  boost::shared_ptr<OldKeyProxy> old_key_proxy_;

protected:
  virtual void on_start_element(conf::ConfParser &parser,
                                const char  *element_name,
                                const char **attribute_names,
                                const char **attribute_values,
                                GError     **error);
  virtual void on_postload();

public:
  inline RefInputEntry mainwindow() {
    return mainwindow_;
  }
  inline RefInputEntry channellist() {
    return channellist_;
  }
  inline RefInputEntry process() {
    return process_;
  }
  inline RefInputEntry peercast() {
    return peercast_;
  }
  inline RefInputEntry pc_relay() {
    return pc_relay_;
  }
  inline RefInputEntry pc_connection() {
    return pc_connection_;
  }
  inline RefInputEntry text_editor() {
    return text_editor_;
  }
  inline RefInputEntry search() {
    return search_;
  }
  inline RefInputEntry searchbar() {
    return searchbar_;
  }
  inline RefInputEntry webview() {
    return webview_;
  }

  ConfInput(const Glib::ustring &dir_path);
};
typedef boost::shared_ptr<ConfInput> RefConfInput;

class Conf {
private:
  sigc::signal<void> signal_loaded_;
public:
  inline sigc::signal<void> signal_loaded() {
    return signal_loaded_;
  }

private:
  Glib::ustring   dir_path_;
  RefConfMain     main_;
  RefConfMenu     menu_;
  RefConfFavorite favorite_;
  RefConfInput    input_;

  bool            loaded_;

public:
  inline const Glib::ustring &get_dir_path() {
    return dir_path_;
  }

  inline RefConfMain main() {
    return main_;
  }
  inline RefConfMenu menu() {
    return menu_;
  }
  inline RefConfFavorite favorite() {
    return favorite_;
  }
  inline RefConfInput input() {
    return input_;
  }

  inline ConfMain::RefGeneral general() {
    return main_->general();
  }
  inline ConfMain::RefScreenSaver screensaver() {
    return main_->screensaver();
  }
  inline ConfMain::RefNetwork network() {
    return main_->network();
  }
  inline ConfMain::RefBuiltInCommand command() {
    return main_->command();
  }
  inline ConfMain::RefRecord record() {
    return main_->record();
  }
  inline ConfMain::RefPresetColors preset_colors() {
    return main_->preset_colors();
  }
  inline ConfMain::RefTerminal terminal() {
    return main_->terminal();
  }
  inline ConfMain::RefSound sound() {
    return main_->sound();
  }
  inline ConfMain::RefMigemo migemo() {
    return main_->migemo();
  }
  inline ConfMain::RefTextEditor text_editor() {
    return main_->text_editor();
  }
  inline ConfMain::RefConfigView config_view() {
    return main_->config_view();
  }

  void load(bool load = true);
  void save();

  inline bool is_loaded() {
    return loaded_;
  }

  Conf(const Glib::ustring &dir_path);
};

}/*gpyp*/

#endif/*CONF_H_*/
